import { AnyMongoAbility, InferSubjects } from '@casl/ability'
import { SetMetadata } from '@nestjs/common'
import { Action } from '../enum/casl.enum'

export enum CHECK_POLICIES_KEY {
  //handler：处理者，操作者 policies：策略 check：检查
  HANDLER = 'CHECK_POLICIES_HANDLER',
  CAN = 'CHECK_POLICIES_CAN',
  CANNOT = 'CHECK_POLICIES_CANNOT'
}

// 策略处理程序回调:PolicyHandlerCallback
export type PolicyHandlerCallback = (ability: AnyMongoAbility) => boolean
// casl处理类型
export type CaslHandlerType = PolicyHandlerCallback | PolicyHandlerCallback[]
// Guards -> routes meta -> @Checkpolicies @Can @Cannot

// CheckPolicies -> handler -> ability ->boolean
// SetMetadata(key: string, value: any)装饰器：通常用于在路由处理程序或守卫中附加元数据。元数据可以用于提供额外的信息给框架或应用程序，进而影响某些功能的行为。

// 疑问1：为什么handers是数组：一个策略检查（handler）可能并不足够，可能需要多个策略函数来处理不同的逻辑或策略。例如，你可能想检查用户的权限、角色，或是否符合某些条件。
// 引入和处理策略（例如权限规则回调），它允许你设置更复杂的访问控制逻辑。
export const CheckPolicies = (...handlers: PolicyHandlerCallback[]) =>
  SetMetadata(CHECK_POLICIES_KEY.HANDLER, handlers)
// @Can -> Action(操作),Subject(实体),Conditions(条件对象)
// AnyMongoAbility：是适用于 MongoDB 的能力对象，帮助你定义和管理用户对资源的访问权限。
// InferSubjects：是一个工具，帮助你根据给定的资源模型推断出权限控制的主题类型，使得权限管理更加灵活和简洁。

//bug：这里注意不要加{},直接=> ，省略return
// 用于为具体操作（如 CRUD）定义权限，结合 AnyMongoAbility 来做基于能力的权限控制。
export const Can = (action: Action, subject: InferSubjects<any>, conditions?: any) =>
  SetMetadata(CHECK_POLICIES_KEY.CAN, (ability: AnyMongoAbility) =>
    ability.can(action, subject, conditions)
  )

// @CanNot -> Action,Subject,Conditions
export const Cannot = (action: Action, subject: InferSubjects<any>, conditions?: any) =>
  SetMetadata(CHECK_POLICIES_KEY.CANNOT, (ability: AnyMongoAbility) =>
    ability.cannot(action, subject, conditions)
  )
